import wx

##  The GH-Joints are estimated in this panel. There are two methods available to calculate the GH-Joints, regression or movement.
class GHJPanel(wx.Panel):

    ## The contructor of GHJPanel. GUI elements of the panel are setup here.
    #   @param[in]  parent  The wx window parent (notebook) of this panel.
    #   @param[in]  state   GHJState instance attached to this panel.
    def __init__(self, parent, state):
        wx.Panel.__init__(self, parent)
        ##  The wx window parent (notebook) of this panel.
        self.parent = parent
        ##  GHJState instance attached to this panel.
        self.state = state
        ##  The name of this notebook panel.        
        self.name = "GH-Joint"

        helptxt = "Select the method to be used for calculating the " \
                  "location of the glenohumeral joint.\n\n" \
                  "The regression method uses the location of the bony landmarks " \
                  "of the scapula, therefore no further action is needed.\n\n" \
                  "The movement method requires the patient to move his/her arm in a " \
                  "circular movement to calculate the centre of rotation."

        self.helpSizer_staticbox = wx.StaticBox(self, -1, "Help")
        self.methodSizer_staticbox = wx.StaticBox(self, -1, "Select Method")
        self.radio_button_regression = wx.RadioButton(self, -1, "Regression")
        self.radio_button_movement = wx.RadioButton(self, -1, "Movement")
        self.static_line_select_method = wx.StaticLine(self, -1)
        ##  "Start/Stop Define Left".
        self.defineButtonL = wx.Button(self, -1, "Start/Stop Define Left")
        ##  "Start/Stop Define Right".
        self.defineButtonR = wx.Button(self, -1, "Start/Stop Define Right")
        ##  "Reset Left".
        self.defineButtonLReset = wx.Button(self, -1, "Reset Left")
        ##  "Reset Right".
        self.defineButtonRReset = wx.Button(self, -1, "Reset Right")
        ##  Upper gauge.
        self.gauge_left = wx.Gauge(self, -1, 50)
        ##  Lower gauge.
        self.gauge_right = wx.Gauge(self, -1, 50)

        self.label_help = wx.StaticText(self, -1, helptxt)

        self.panel_1 = wx.Panel(self, -1)
        self.panel_2 = wx.Panel(self, -1)
        self.panel_3 = wx.Panel(self, -1)
        self.panel_4 = wx.Panel(self, -1)
        self.panel_5 = wx.Panel(self, -1)
        self.panel_6 = wx.Panel(self, -1)
        self.static_line_1 = wx.StaticLine(self, -1)
        self.static_line_2 = wx.StaticLine(self, -1)
        self.static_line_3 = wx.StaticLine(self, -1)
        ##  Goes to the previous panel.
        self.ghBackButton = wx.Button(self, -1, "< Back")
        ##  Goes to the next panel.
        self.ghFinishButton = wx.Button(self, -1, "Finish")
        ##  Timer associated with gauge_left.
        self.timerLeft = wx.Timer(self, 1)
        ##  Timer associated with gauge_right.
        self.timerRight = wx.Timer(self, 2)
        ##  Boolean indicating whether the left GH-Joint has been calculated.
        self.leftCalculated = False
        ##  Boolean indicating whether the right GH-Joint has been calculated.
        self.rightCalculated = False
        ##  Makes sure gauge_left stops running when defineButtonL is pressed for the second time.
        self.leftCalled = 0
        ##  Makes sure gauge_right stops running when defineButtonR is pressed for the second time.
        self.rightCalled = 0
        ##  Process indicator for the gauges.
        self.count = 0

        self.__BindEvents()
        self.__SetProperties()
        self.__DoLayout()
        
        self.OnRadioButton(None)

    ##  Sets several properties for the panel.
    def __SetProperties(self):
        self.defineButtonL.Disable()
        self.defineButtonR.Disable()
        self.defineButtonL.Enable()
        self.defineButtonR.Enable()
        self.gauge_left.SetMinSize((300, 20))
        self.gauge_right.SetMinSize((300, 20))
        self.label_help.SetMinSize((150, 254))
        
        self.radio_button_regression.SetValue(1)

    ##  Sets layout for the panel elements.
    def __DoLayout(self):
        grid_sizer_menu_top = wx.FlexGridSizer(4, 3, 0, 0)
        grid_sizer_menu_bottom = wx.FlexGridSizer(1, 2, 0, 10)
        ghHelp = wx.StaticBoxSizer(self.helpSizer_staticbox, wx.HORIZONTAL)
        ghSizer = wx.StaticBoxSizer(self.methodSizer_staticbox, wx.HORIZONTAL)
        
        grid_sizer_select_method = wx.FlexGridSizer(4, 1, 0, 0)
        grid_sizer_select_method.Add(self.radio_button_regression, 0, wx.BOTTOM, 10)
        grid_sizer_select_method.Add(self.radio_button_movement, 0, wx.BOTTOM, 5)
        grid_sizer_select_method.Add(self.static_line_select_method, 0, wx.BOTTOM|wx.EXPAND, 10)

        grid_sizer_select_method_sub = wx.FlexGridSizer(2, 3, 0, 0)
        grid_sizer_select_method_sub.Add(self.defineButtonL, 0, wx.RIGHT, 10)
        grid_sizer_select_method_sub.Add(self.defineButtonLReset, 0, wx.RIGHT, 10)
        grid_sizer_select_method_sub.Add(self.gauge_left, 0, wx.LEFT, 0)

        grid_sizer_select_method_sub.Add(self.defineButtonR, 0, wx.RIGHT, 10)
        grid_sizer_select_method_sub.Add(self.defineButtonRReset, 0, wx.RIGHT, 10)
        grid_sizer_select_method_sub.Add(self.gauge_right, 0, wx.LEFT, 0)
        grid_sizer_select_method_sub.AddGrowableCol(1)

        grid_sizer_select_method.Add(grid_sizer_select_method_sub, 1, wx.EXPAND, 0)
        ghSizer.Add(grid_sizer_select_method, 1, wx.ALL|wx.EXPAND, 10)

        ghHelp.Add(self.label_help, 0, wx.ALL, 10)

        grid_sizer_menu_top.Add(ghSizer, 1, wx.ALL, 10)
        grid_sizer_menu_top.Add(self.panel_1, 1, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(ghHelp, 1, wx.ALL|wx.ALIGN_RIGHT, 10)
        grid_sizer_menu_top.Add(self.panel_4, 1, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(self.panel_6, 1, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(self.panel_2, 1, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(self.static_line_1, 0, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(self.static_line_2, 0, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(self.static_line_3, 0, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(self.panel_3, 1, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(self.panel_5, 1, wx.EXPAND, 0)
        grid_sizer_menu_top.Add(grid_sizer_menu_bottom, 1, wx.TOP|wx.BOTTOM|wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM, 5)

        grid_sizer_menu_top.AddGrowableRow(1)
        grid_sizer_menu_top.AddGrowableCol(2)
        
        grid_sizer_menu_bottom.Add(self.ghBackButton, 0, wx.ALIGN_RIGHT, 0)
        grid_sizer_menu_bottom.Add(self.ghFinishButton, 0, wx.RIGHT|wx.ALIGN_RIGHT, 10)

        self.SetSizer(grid_sizer_menu_top)
        grid_sizer_menu_top.Fit(self)
        self.Layout()

    ##  Binds the panel elements to event handlers.
    def __BindEvents(self):
        self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, id=self.radio_button_movement.GetId())
        self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, id=self.radio_button_regression.GetId())
       
        self.Bind(wx.EVT_BUTTON, self.OnDefineLeft, id=self.defineButtonL.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnDefineRight, id=self.defineButtonR.GetId())

        self.Bind(wx.EVT_BUTTON, self.OnDefineLeftReset, id=self.defineButtonLReset.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnDefineRightReset, id=self.defineButtonRReset.GetId())

        self.Bind(wx.EVT_TIMER, self.OnTimerLeft, self.timerLeft)
        self.Bind(wx.EVT_TIMER, self.OnTimerRight, self.timerRight)

        self.Bind(wx.EVT_BUTTON, self.OnBack, self.ghBackButton)
        self.Bind(wx.EVT_BUTTON, self.OnNext, self.ghFinishButton)

    ##  Disables or enables the define buttons depending on which radiobutton is enabled.
    def OnRadioButton(self, event):

        self.EventWhileMeasuring()

        if self.radio_button_movement.GetValue():
            msg = "The movement method can not be used in this program version, no GH-Joints will be calculated."
            dlg = wx.MessageDialog(self.state.main.gui, msg, 'Warning', wx.OK | wx.NO_DEFAULT | wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            if not self.leftCalculated:
                self.defineButtonL.Enable()
                self.defineButtonLReset.Disable()
            else:
                self.defineButtonL.Disable()
                self.defineButtonLReset.Enable()

            if not self.rightCalculated:
                self.defineButtonR.Enable()
                self.defineButtonRReset.Disable()
            else:
                self.defineButtonR.Disable()
                self.defineButtonRReset.Enable()
        else:
            self.defineButtonL.Disable()
            self.defineButtonR.Disable()
            self.defineButtonLReset.Disable()
            self.defineButtonRReset.Disable()

    ##  Event handler for the left GH-Joint Define button.
    def OnDefineLeft(self, event):
        self.leftCalled += 1

        # Disable the define and reset button of the right GH-Joint.
        self.defineButtonR.Disable()
        self.defineButtonRReset.Disable()

        # If the define button has been pressed for the second time, the user indicates the measurement is complete.
        if self.leftCalled == 2:

            self.timerLeft.Stop()
            self.gauge_left.SetValue(50)
            self.leftCalculated = True

            # Disable the define button, and enable the reset button.
            self.defineButtonL.Disable()
            self.defineButtonLReset.Enable()

            # Reset the value.
            self.leftCalled = 0
            self.count = 0

            # Check whether the right Joint has been measurement is completed, and set the dialog message and the buttons according to the situation.
            if self.rightCalculated:
                msg = "Left GH-Joint calculation is complete. All Joints have now been calculated. You can now proceed to visualization."
                self.defineButtonRReset.Enable()
            else: 
                msg = "Left GH-Joint calculation is completed. You may now calculate the right GH-Joint or proceed to visualization."
                self.defineButtonR.Enable()

            dlg = wx.MessageDialog(self, msg, 'Measurement completed', wx.OK | wx.ICON_INFORMATION)
            dlg.ShowModal()

            return

        self.timerLeft.Start(100)

    ##  Event handler for the right GH-Joint Define button.
    def OnDefineRight(self, event):
        self.rightCalled += 1
        
        # Disable the define and reset button of the left GH-Joint
        self.defineButtonL.Disable()
        self.defineButtonLReset.Disable()

        # If the define button has been pressed for the second time, the user indicates the measurement is complete.
        if self.rightCalled == 2:

            self.timerRight.Stop()
            self.gauge_right.SetValue(50)
            self.rightCalculated = True

            # Disable the define button, and enable the reset button.
            self.defineButtonR.Disable()
            self.defineButtonRReset.Enable()

            # Reset the value.
            self.rightCalled = 0
            self.count = 0

            # Check whether the right GH-Joint has been measurement, and set the dialog message and the buttons according to the situation.
            if self.leftCalculated:
                msg = "Right GH-Joint calculation is complete. All Joints have now been calculated. You can now proceed to the visualization."
                self.defineButtonLReset.Enable()
            else: 
                msg = "Right GH-Joint calculation is complete. You may now calculate the left GH-Joint or proceed to visualization."
                self.defineButtonL.Enable()

            dlg = wx.MessageDialog(self, msg, 'Measurement completed', wx.OK | wx.ICON_INFORMATION)
            dlg.ShowModal()
            
            return

        self.timerRight.Start(100)

    ##  Event handler for the Define Left Reset Button, resets the measurements.
    def OnDefineLeftReset(self, event):
        msg = "Are you sure you want to reset the left GH-Joint calculation?"
        dlg = wx.MessageDialog(self, msg, 'Confirm deletion', wx.YES_NO | wx.ICON_EXCLAMATION)
        if(dlg.ShowModal() == wx.ID_YES):
            self.leftCalculated = False
            self.defineButtonL.Enable()
            self.defineButtonLReset.Disable()
            self.gauge_left.SetValue(0)
        dlg.Destroy()

    ##  Event handler for the Define Right Reset Button, resets the measurements.
    def OnDefineRightReset(self, event):
        msg = "Are you sure you want to reset the right GH-Joint calculation?"
        dlg = wx.MessageDialog(self, msg, 'Confirm deletion', wx.YES_NO | wx.ICON_EXCLAMATION)
        if(dlg.ShowModal() == wx.ID_YES):
            self.rightCalculated = False
            self.defineButtonR.Enable()
            self.defineButtonRReset.Disable()
            self.gauge_right.SetValue(0)
        dlg.Destroy()

    ##  Event handler for the Timer belonging to the left GH-Joint gauge.
    def OnTimerLeft(self, event):
        self.count = self.count +1
        self.gauge_left.SetValue(self.count)
        if self.count == 50:
            self.count = 0

    ##  Event handler for the Timer belonging to the right GH-Joint gauge.
    def OnTimerRight(self, event):
        self.count = self.count +1
        self.gauge_right.SetValue(self.count)
        if self.count == 50:
            self.count = 0

    ##  Panel navigation, goes back in the panel navigation to the previous state.
    #   @param[in]  new   The tab index to go to.
    def OnBack(self, event, new = 1):
        self.parent.ChangeSelection(new)
        self.EventWhileMeasuring()

    ##  Handles events when the finished button is pressed.
    #   @param[in]  new     The tab index to go to.
    #   @return[boolean]    False when navigation to following panel is somehow cancelled, else True.
    def OnNext(self, event, new = 3):
        if self.radio_button_movement.GetValue():
                self.state.CalcMovementMethod()
        else:
                self.state.CalcRegressionMethod()


        NAVIGATED_TO_NEXT = False

        self.parent.ChangeSelection(new)

        self.EventWhileMeasuring()

        self.state.main.states.visualization.OnTogglePlayPause()

        NAVIGATED_TO_NEXT = True
        return NAVIGATED_TO_NEXT

    ##  If an event is triggered while measuring, this method will provide a dialogue on whether or not the event should proceed.
    def EventWhileMeasuring(self):
        if( self.leftCalled or self.rightCalled):
            msg = "You were in the process of calculating a GH-Joint. This process has now been cancelled."
            dlg = wx.MessageDialog(self, msg, 'Confirm action', wx.OK | wx.ICON_EXCLAMATION)

            if(dlg.ShowModal() == wx.ID_OK):
                if self.leftCalled == 1:
                    self.gauge_left.SetValue(0)
                    self.timerLeft.Stop()
                    self.leftCalled = 0
                    if self.rightCalculated:
                        self.defineButtonRReset.Enable()
                    else: self.defineButtonR.Enable()

                if self.rightCalled == 1:
                    self.gauge_right.SetValue(0)
                    self.timerRight.Stop()
                    self.rightCalled = 0
                    if self.leftCalculated:
                        self.defineButtonLReset.Enable()
                    else: self.defineButtonL.Enable()

            dlg.Destroy()
